package com.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.entity.MPost;
import com.mapper.MPostMapper;
import com.service.MPostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.utils.RedisUtil;
import com.vo.PostVo;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 公众号：java思维导图
 * @since 2020-12-13
 */
@Service
public class MPostServiceImpl extends ServiceImpl<MPostMapper, MPost> implements MPostService {
    @Autowired
    MPostMapper postMapper;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    HttpServletRequest request;

    @Override
    public IPage<PostVo> paging(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {

        if(level==null)level=-1;

        QueryWrapper<MPost> wrapper = new QueryWrapper<MPost>()
                .eq(categoryId != null, "category_id", categoryId)
                .eq(userId != null, "user_id", userId)
                .eq(level == 0, "level", 0)
                .gt(level > 0, "level", 0)
                .orderByDesc(order != null, order);
        return postMapper.selectPosts(page,wrapper);
    }

    @Override
    public PostVo selectOnePost(Long id) {
        QueryWrapper<MPost> wrapper = new QueryWrapper<MPost>()
                .eq("p.id", id);
        return postMapper.selectOnePost(wrapper);
    }

    /**
     * 本周热议功能的实现
     */
    @Override
    public void initWeekRank() {
        //查询多篇文章（七天内发表的文章）
        List<MPost> posts = this.list(new QueryWrapper<MPost>()
            .ge("created", DateUtil.offsetDay(new Date(), -7))
            .select("id, title, user_id, comment_count, view_count, created")
        );
        //初始化文章的总评论量
        for (MPost post:posts) {
            String key="day:rank:"+DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_PATTERN);
            redisUtil.zSet(key, post.getId(), post.getCommentCount());
            //设置过期时间：七天内自动过期
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 60 * 60 * 24;
            redisUtil.expire(key, expireTime);

            //缓存文章的一些基本信息（id、标题、评论数量、作者）
            this.hashCachePostIdAndTitle(post,expireTime);
        }
        // 做并集
        this.zunionAndStoreLast7DayForWeekRank();
    }
    /**
     * 缓存文章的一些基本信息（id、标题、评论数量、作者）
     */
    private void hashCachePostIdAndTitle(MPost post, long expireTime) {
        String key="rank:post:"+post.getId();
        boolean hasKey = redisUtil.hasKey(key);
        if (!hasKey){
            redisUtil.hset(key, "post:id",post.getId(),expireTime);
            redisUtil.hset(key, "post:title",post.getTitle(),expireTime);
            redisUtil.hset(key, "post:commentCount",post.getCommentCount(),expireTime);
            redisUtil.hset(key, "post:viewCount",post.getViewCount(),expireTime);
        }
       /*     Object hget = redisUtil.hget("rank:post:2", "post:title");
            System.out.println(hget.toString());获取标题内容*/
    }
    //将七天内发表的文章合并到一个集合中去
    private void zunionAndStoreLast7DayForWeekRank()  {
        String  currentKey = "day:rank:" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
        String destKey = "week:rank";
        List<String> otherKeys = new ArrayList<>();
        for(int i=-6; i < 0; i++) {
            String temp = "day:rank:" +
                    DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);
            otherKeys.add(temp);
        }
        /**
         currentKey：今天的  otherKeys：前六天的  destKey:今天和之前的合并之后的*/
        redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);
    }
    /**
     * 文章评论数量更新及其之后的本周热议功能
     */
    @Override
    public void incrCommentCountAndUnionForWeekRank(long postId, boolean isIncr) {
        String currentKey="day:rank:"+DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        redisUtil.zIncrementScore(currentKey, postId, isIncr?1:-1);
        MPost post = this.getById(postId);

        // 7天后自动过期(15号发表，7-（18-15）=4)
        long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
        long expireTime = (7 - between) * 24 * 60 * 60; // 有效时间

        //重新缓存这篇文章的基本信息
        this.hashCachePostIdAndTitle(post, expireTime);
        // 重新做并集
        this.zunionAndStoreLast7DayForWeekRank();

    }

    /**
     * 浏览量的+1 操作,根据客户端IP进行限制
     * @param vo
     */
    @Override
    public void putViewCount(PostVo vo) {
        String key="rank:post:"+vo.getId();

        //1、从缓存中获取viewCount;
        Integer viewCount = (Integer) redisUtil.hget(key, "post:viewCount");

        //获取客户端IP
        String ip = request.getRemoteAddr();
        System.out.println(ip);
        if (!redisUtil.hHasKey("user:ip", ip)){
            //2、viewCount+1操作 如果缓存中没有，则先从实体类中获取
            if (viewCount!=null){
                vo.setViewCount(viewCount+1);
            }else {
                vo.setViewCount(vo.getViewCount()+1);
            }
            redisUtil.hset("user:ip", ip, ip);
        }

        //3、同步数据到缓存中
        redisUtil.hset(key, "post:viewCount", vo.getViewCount());
    }
}
